home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / AdobeExamples / NX_Text / DrawingView.m < prev    next >
Encoding:
Text File  |  1992-12-19  |  15.6 KB  |  757 lines

  1.  
  2. /*
  3.  * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
  4.  *
  5.  * (b)  If this Sample Code is distributed as part of the Display PostScript
  6.  *    System Software Development Kit from Adobe Systems Incorporated,
  7.  *    then this copy is designated as Development Software and its use is
  8.  *    subject to the terms of the License Agreement attached to such Kit.
  9.  *
  10.  * (c)  If this Sample Code is distributed independently, then the following
  11.  *    terms apply:
  12.  *
  13.  * (d)  This file may be freely copied and redistributed as long as:
  14.  *    1) Parts (a), (d), (e) and (f) continue to be included in the file,
  15.  *    2) If the file has been modified in any way, a notice of such
  16.  *      modification is conspicuously indicated.
  17.  *
  18.  * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
  19.  *    Adobe Systems Incorporated.
  20.  * 
  21.  * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
  22.  *    CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
  23.  *    AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
  24.  *    ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
  25.  *    OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
  26.  *    WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
  27.  *    WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
  28.  *    DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
  29.  *    FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
  30.  *    OF THIRD PARTY RIGHTS.
  31.  */
  32.  
  33. /*
  34.  *    DrawingView.m
  35.  *
  36.  *    This view represents the page that the image is drawn onto. It is
  37.  *    a subview of the DocView. The DocView is the document view of
  38.  *    the ClipView. This view's real size grows with the scale but the
  39.  *    bounds always stays the same.
  40.  *
  41.  *    Version:    2.0
  42.  *    Author:    Ken Fromm
  43.  *    History:
  44.  *            03-07-91        Added this comment.
  45.  */
  46.  
  47. #import "DrawingView.h"
  48. #import "DrawingViewWraps.h"
  49. #import "DocView.h"
  50. #import "TextApp.h"
  51.  
  52. #import "hdshowaux.h"
  53.  
  54. #import <appkit/Button.h>
  55. #import <appkit/Cell.h>
  56. #import <appkit/Font.h>
  57. #import <appkit/Matrix.h>
  58. #import <appkit/nextstd.h>
  59.  
  60. #import <dpsclient/dpsclient.h>
  61. #import <dpsclient/wraps.h>
  62.  
  63. #import <ctype.h>
  64.  
  65. extern char*const    textstrings[];
  66. extern float        textstart[][2];
  67.  
  68. @implementation DrawingView
  69.  
  70. /*
  71. *    Allocate a gstate, set the clipping to NO because it will be clipped
  72. *    by the clip view.
  73. */
  74. +newFrame:(NXRect *) frm
  75. {
  76.     id        font;
  77.  
  78.     self = [super newFrame:frm]; 
  79.  
  80.     [[[self allocateGState] setClipping:NO]  setFlipped:YES]; 
  81.     NX_MALLOC(charspace, NXCoord, MAX_XSHOW);
  82.     AllocShowStruct(&s);
  83.  
  84.     showtype = XSHOW;                /* use xshow */
  85.     cache = YES;                        /* use font cache */
  86.  
  87.     fontsize = FONTSIZE;
  88.     font = [Font  newFont:"Times-Roman"  size:fontsize];
  89.     PSWCopyFont("Times-Roman", "Times-RomanOutline");
  90.     
  91.     PSWCurrentcacheparams(&size, &lower, &upper);
  92.  
  93.     return self;
  94. }
  95.  
  96. - free
  97. {
  98.     PSWSetcacheparams(size, lower, upper);
  99.     NXPing();
  100.  
  101.     NX_FREE(charspace);
  102.     FreeShowStruct(&s);
  103.  
  104.     return [super free];
  105. }
  106.  
  107. - (int) rotation
  108. {
  109.     return rotation;
  110. }
  111.  
  112. - fontsize:sender
  113. {
  114.     fontsize = atof([[sender  selectedCell]  title]);
  115.  
  116.     [self  reshow:self];
  117.  
  118.     return self;
  119. }
  120.  
  121. - justify:sender
  122. {
  123.     justify = ([sender selectedTag] != 0);  
  124.     [self  reshow:self];
  125.  
  126.     return self;
  127. }
  128.  
  129. - kern:sender
  130. {
  131.     kern = [[sender selectedCell]  state];
  132.     [self  reshow:self];
  133.  
  134.     return self;
  135. }
  136.  
  137. - track:sender
  138. {
  139.     track = [[sender selectedCell]  state];
  140.     [self  reshow:self];
  141.  
  142.     return self;
  143. }
  144.  
  145. /*
  146. *    Sets the font cache to an arbitrarily low size. It's almost never necessary
  147. *    to change the font cache size. This is only here to provide some
  148. *    demonstration of the effectiveness of the font cache. Its operation is
  149. *    best left alone.
  150. */
  151. - cache:sender
  152. {
  153.     cache = [[sender selectedCell]  state];  
  154.     if (cache)
  155.         PSWSetcacheparams(size, lower, upper);
  156.     else
  157.         PSWSetcacheparams(0, 0, 0);
  158.     
  159.     [self  reshow:self];
  160.  
  161.     return self;
  162. }
  163.  
  164. - outline:sender
  165. {
  166.     outline = [[sender selectedCell]  state];
  167.     [self  reshow:self];
  168.  
  169.     return self;
  170. }
  171.  
  172. - show:sender
  173. {
  174.     showtype = [sender selectedTag];  
  175.     [self  reshow:self];
  176.  
  177.     return self;
  178. }
  179.  
  180. - compareKerns:sender
  181. {
  182.     id        cell;
  183.  
  184.     compareKern = [[sender  selectedCell]  state];
  185.     if (compareKern && compareWidths)
  186.     {
  187.         compareWidths = NO;
  188.         cell = [[NXApp  comparisonsMatrix]  findCellWithTag:WIDTH_TAG];
  189.         [cell  setState:NO];
  190.         [[cell controlView]  drawCell:cell];
  191.     }
  192.  
  193.     [self  reshow:self];
  194.  
  195.     return self;
  196. }
  197.  
  198. - compareWidths:sender
  199. {
  200.     id        cell;
  201.  
  202.     compareWidths = [[sender  selectedCell]  state];
  203.     if (compareWidths && compareKern)
  204.     {
  205.         compareKern = NO;
  206.         cell = [[NXApp  comparisonsMatrix]  findCellWithTag:KERN_TAG];
  207.         [cell  setState:NO];
  208.         [[cell controlView]  drawCell:cell];
  209.     }
  210.  
  211.     [self  reshow:self];
  212.  
  213.     return self;
  214. }
  215.  
  216. - rotate:sender
  217. {
  218.     id            field;
  219.  
  220.     field = [NXApp rotationField];
  221.  
  222.     if (sender == field)
  223.         rotation = atoi([field  stringValue]);
  224.     else if ([sender selectedTag] == 0)
  225.         rotation += ROTATION;
  226.     else
  227.         rotation -= ROTATION;
  228.  
  229.     rotation = rotation % 360;
  230.     [field  setIntValue:rotation];
  231.  
  232.     [self  resetFields:self];
  233.     [self  rotateTo:(float) rotation];
  234.     [superview  rotateDrawView];
  235.     [self  displayFields:self];
  236.  
  237.     return self;
  238. }
  239.  
  240. /*
  241. *    Changes the title of the menu cell according
  242. *    to the value of the trace variable.
  243. */
  244. -trace:sender
  245. {
  246.     if (trace == NO)
  247.         [[sender selectedCell] setTitle:"Trace On"];
  248.     else
  249.         [[sender selectedCell] setTitle:"Trace Off"];
  250.  
  251.     trace = !trace;
  252.     
  253.     return self;
  254. }
  255.  
  256. - eraseFields:sender
  257. {
  258.     id        matrixId;
  259.  
  260.     int        i;
  261.  
  262.     matrixId = [NXApp  timingMatrix];
  263.     for (i= 0; i < [matrixId cellCount]; i++)
  264.         [[matrixId cellAt:i :0] setStringValue:""];
  265.  
  266.     matrixId = [NXApp  statusMatrix];
  267.     for (i= 0; i < [matrixId cellCount]; i++)
  268.         [[matrixId cellAt:i :0] setStringValue:""];
  269.  
  270.     eraseFields = NO;
  271.  
  272.     return self;
  273. }
  274.  
  275. - resetFields:sender
  276. {
  277.     /* Prepare for next time around. */
  278.     timing_info.chars = timing_info.reshows = timing_info.kerns = timing_info.time = 0;
  279.  
  280.     return self;
  281. }
  282.  
  283. - displayFields:sender
  284. {
  285.     id        matrixId;
  286.  
  287.     int        i, cvalues[7];
  288.     
  289.      if (timing_info.reshows)
  290.     {
  291.         matrixId = [NXApp timingMatrix];
  292.         [[matrixId cellAt:0 :0]  setIntValue:rint(timing_info.time/timing_info.reshows)];
  293.         [[matrixId cellAt:1 :0]  setIntValue:rint(timing_info.chars/timing_info.reshows)];
  294.         [[matrixId cellAt:2 :0]  setIntValue:rint(timing_info.kerns/timing_info.reshows)];
  295.  
  296.         matrixId = [NXApp statusMatrix];
  297.         PSWCachestatus(cvalues);
  298.         for (i= 0; i < [matrixId  cellCount]; i++)
  299.             [[matrixId cellAt:i :0] setIntValue:cvalues[i]];
  300.  
  301.     }
  302.  
  303.     [self  resetFields:self];
  304.     eraseFields = YES;
  305.  
  306.     return self;
  307. }
  308.  
  309. - reshow:sender
  310. {
  311.     NXRect    visRect;
  312.  
  313.     eraseFields = NO;
  314.  
  315.     [self  resetFields:self];
  316.     [self  getVisibleRect:&visRect];
  317.     [self  display:&visRect :1];
  318.  
  319.     [self  displayFields:self];
  320.  
  321.     return self;
  322. }
  323.  
  324. /*
  325. *    If the docview is zooming, then scale the drawing view.
  326. */
  327. - mouseDown:(NXEvent *)event
  328. {
  329.     NXPoint        p;
  330.     
  331.      p = event->location; 
  332.     if ([superview  isZooming])
  333.     {
  334.         eraseFields = NO;
  335.         [self  resetFields:self];
  336.         [superview  scaleDrawViewToPoint:&p];
  337.         [self  displayFields:self];
  338.     }
  339.  
  340.     return self;
  341. }
  342.  
  343. static NXCoord filltrackwidths(char *str, float *array, ShowStruct *s, float value)
  344. {
  345.     int            i, len;
  346.  
  347.     NXCoord        trackwidth = 0.0;
  348.  
  349.     if (str && value)
  350.     {
  351.         len = strlen(str);
  352.         if (array)
  353.         {
  354.             for (i = 0; i < len; i++)
  355.                 array[i] += value;
  356.         }
  357.         else if (s)
  358.             AddTracking(s, 0, value);
  359.  
  360.         trackwidth = len * value;
  361.     }
  362.  
  363.     return trackwidth;
  364. }
  365.  
  366. static void fillspacewidths(char *str, float *array, ShowStruct *s, float value)
  367. {
  368.     int            i, len;
  369.  
  370.     if (str && value)
  371.     {
  372.         if (array)
  373.         {
  374.             len = strlen(str);
  375.             for (i = 0; i < len; i++)
  376.                 if (str[i] == ' ')
  377.                     array[i] += value;
  378.         }
  379.         else if (s)
  380.             AddSpaceAdj(s, 0, value);
  381.     }
  382. }
  383.  
  384. /*
  385. *    If an array is passed in then place the character width for each character
  386. *    in str in it (used when displaying with xshow). Also keep track of the total width
  387. *    and the number of spaces and return the value of the width divided by the
  388. *    spaces (used when displaying with full justification).
  389. */
  390. static NXCoord fillstringwidths(char *str, NXFontMetrics *metrics, float *array, float fontsize, NXCoord kernwidth, NXCoord trackwidth)
  391. {
  392.     BOOL        nospacing = NO;
  393.  
  394.     int            i, len,
  395.                 spaces;
  396.  
  397.     NXCoord        value,
  398.                 linewidth;
  399.  
  400.     spaces = 0;
  401.     linewidth = kernwidth + trackwidth;
  402.     if (str && metrics && metrics->widths)
  403.     {
  404.         len = strlen(str);
  405.         for (i = 0; i < len; i++)
  406.         {
  407.             value = metrics->widths[(unsigned char)str[i]] * fontsize;
  408.             linewidth += value;
  409.             if (array)
  410.                 array[i] += value;
  411.  
  412.             /* Check for space, return, linefeed, etc. */
  413.             if(isspace(str[i]))
  414.             {
  415.                 if (str[i] == ' ')
  416.                     spaces ++;
  417.                 else
  418.                     nospacing = YES;
  419.             }
  420.         }
  421.     }
  422.  
  423.     if (spaces == 0)
  424.         value = 0.0;
  425.     else
  426.     {
  427.         if (trackwidth)
  428.             value = (LINE_LENGTH_TR - linewidth)/spaces;
  429.         else
  430.             value = (LINE_LENGTH - linewidth)/spaces;
  431.         if (nospacing && value > 0)
  432.             value = 0.0;
  433.     }
  434.  
  435.     return value;
  436. }
  437.  
  438. /*
  439. *    Look up the kern pairs for the first character and see if
  440. *    there is an entry for the second character. Returns the
  441. *    value to kern if any.
  442. */
  443. static NXCoord getkernvalue(NXFontMetrics *metrics, unsigned char char1, unsigned char char2)
  444. {
  445.     int            enc1, enc2,
  446.                 i, kindex, klen;
  447.  
  448.     NXCoord        value = 0.0;
  449.  
  450.     enc1 = metrics->encoding[char1]; 
  451.     enc2 = metrics->encoding[char2];
  452.     if (enc1 < metrics->numCharMetrics && enc2 < metrics->numCharMetrics)
  453.     {
  454.         kindex = metrics->charMetrics[enc1].kernPairIndex;
  455.         klen = metrics->charMetrics[enc1].numKernPairs;
  456.         if (kindex+klen < metrics->numKernPairs)
  457.         {
  458.             for (i = kindex; i < kindex + klen; i++)
  459.             {
  460.                 if (metrics->hasXYKerns)
  461.                 {
  462.                       if (enc2 == metrics->kerns.kernPairs[i].secondCharIndex)
  463.                     {
  464.                         value = metrics->kerns.kernPairs[i].dx;
  465.                         break;
  466.                     }
  467.                 }
  468.                 else
  469.                 {
  470.                     if (enc2 == metrics->kerns.kernXPairs[i].secondCharIndex)
  471.                     {
  472.                         value = metrics->kerns.kernXPairs[i].dx;
  473.                         break;
  474.                     }
  475.                 }
  476.             }
  477.         }
  478.     }
  479.  
  480.     return value;
  481. }
  482.  
  483. static NXCoord fillkernwidths(char *str, NXFontMetrics *metrics, float *array, ShowStruct *s, float fontsize, int *kerns)
  484. {
  485.     int            i, len;
  486.  
  487.     NXCoord        value,
  488.                 kernwidth;
  489.  
  490.     kernwidth = 0.0;
  491.     if (str && metrics)
  492.     {
  493.         len = strlen(str) -1;
  494.         for (i = 0; i < len; i++)
  495.         {
  496.             if (value = getkernvalue(metrics, (unsigned char) str[i], (unsigned char) str[i+1]))
  497.             {
  498.                 value = value * fontsize;
  499.                 if (array)
  500.                     array[i] += value;
  501.                 else if (s)
  502.                     AddPairKern(s, i+1, value);
  503.             
  504.                 kernwidth += value;
  505.                 (*kerns)++;
  506.             }
  507.         }
  508.     }
  509.  
  510.     return kernwidth;
  511. }
  512.  
  513. /*
  514. *    Go through the line and insert the appropriate value into the array.
  515. *    The value placed in is dependent on whether we are kerning or not
  516. *    and whether we are using xshow or not. If kerning, then look up each
  517. *    pair in the AFM kerning array. If using xshow, then include the
  518. *    character width in the array as well (xshow takes the displacement from
  519. *    the previously shown character hence the character width).
  520. *    The fontsize is used to scale the kerning value and the character width.
  521. *    In a screenfont, no adjustment is necessary because the values are
  522. *    already scaled to the appropriate values.
  523. */
  524. static int  characterspacing(id  font, char *str, NXCoord *array, BOOL justify, BOOL kern, BOOL track, BOOL width)
  525. {
  526.     int            kerns = 0;
  527.  
  528.     float            fontsize;
  529.  
  530.     NXCoord        kernwidth,
  531.                 spacewidth,
  532.                 trackwidth;
  533.  
  534.     NXFontMetrics    *metrics;
  535.  
  536.     bzero(array, MAX_XSHOW*sizeof(NXCoord));
  537.  
  538.     metrics = [font  readMetrics:FONTMETRICS];
  539.     if (metrics)
  540.     {
  541.         if (metrics->isScreenFont)
  542.             fontsize = 1;
  543.         else
  544.             fontsize = [font  pointSize];
  545.  
  546.         kernwidth = spacewidth = trackwidth = 0.0;
  547.  
  548.         if (kern && metrics->encoding && metrics->charMetrics)
  549.             kernwidth = fillkernwidths(str, metrics, array, NULL, fontsize, &kerns);
  550.  
  551.         if (track)
  552.             trackwidth = filltrackwidths(str, array, NULL, TRACKVAL);
  553.  
  554.         if (width && metrics->widths)
  555.             spacewidth = fillstringwidths(str, metrics, array, fontsize, kernwidth, trackwidth);
  556.     
  557.         if (justify)
  558.         {
  559.             if (!width && metrics->widths)
  560.                 spacewidth = fillstringwidths(str, metrics, NULL, fontsize,
  561.                                 kernwidth, trackwidth);
  562.             fillspacewidths(str, array, NULL, spacewidth);
  563.         }
  564.     }
  565.  
  566.     return kerns;
  567. }
  568.  
  569. static int  showstructure(id  font, char *str, ShowStruct *s, BOOL justify, BOOL kern, BOOL track)
  570. {
  571.     int            kerns = 0;
  572.  
  573.     float            fontsize;
  574.  
  575.     NXCoord        kernwidth,
  576.                 spacewidth,
  577.                 trackwidth;
  578.  
  579.     NXFontMetrics    *metrics;
  580.  
  581.     metrics = [font  readMetrics:FONTMETRICS];
  582.     if (metrics)
  583.     {
  584.         if (metrics->isScreenFont)
  585.             fontsize = 1;
  586.         else
  587.             fontsize = [font  pointSize];
  588.  
  589.         kernwidth = spacewidth = trackwidth = 0.0;
  590.         if (kern && metrics->encoding && metrics->charMetrics)
  591.             kernwidth = fillkernwidths(str, metrics, NULL, s, fontsize, &kerns);
  592.     
  593.         if (track)
  594.             trackwidth = filltrackwidths(str, NULL, s, TRACKVAL);
  595.  
  596.         if (justify)
  597.         {
  598.             spacewidth = fillstringwidths(str, metrics, NULL, fontsize, kernwidth, trackwidth);
  599.             fillspacewidths(str, NULL, s, spacewidth);
  600.         }
  601.  
  602.     }
  603.  
  604.     return kerns;
  605. }
  606.  
  607. /*
  608. *    Set the font either to the printer font or the screenfont, turn the trace on
  609. *    if tracing and then mark the time. (The last two steps are for demonstration
  610. *    purposes only. Cycle through the static array of text checking if a line
  611. *    intersects the rectangle passed in. If so then draw it according to the values
  612. *    set in the interface - kerning or no kerning, screen widths or printer widths,
  613. *    xshow or rmoveto/show, etc. 
  614. */
  615. - showText:(const NXRect *)r
  616. {
  617.     id            font;
  618.  
  619.     float             x;
  620.  
  621.     int            i, j, last,
  622.                 chars,
  623.                 ElapsedTime;
  624.  
  625.     NXRect        textRect;
  626.  
  627.     if (trace)
  628.         DPSTraceContext(DPSGetCurrentContext(), YES);
  629.  
  630.     font = [Font  newFont:"Times-Roman"  size:fontsize];
  631.     if (outline)
  632.         PSWSetFont("Times-RomanOutline", fontsize);
  633.     else
  634.         [font  set];
  635.  
  636.     if (screen && [font  screenFont])
  637.         font = [font  screenFont];
  638.  
  639.     textRect.origin.x = bounds.origin.x;
  640.     textRect.size.width = bounds.size.width;
  641.     textRect.size.height = 2 * fontsize;
  642.  
  643.     PSsetwindowtype(NX_RETAINED, [window  windowNum]);
  644.     PSWMarkTime();  NXPing();
  645.     for (i = 0; i < NUM_LINES; i++)
  646.     {
  647.         textRect.origin.y = textstart[i][1] - fontsize;
  648.         if (NXIntersectsRect(r, &textRect))
  649.         {
  650.             chars = strlen(textstrings[i]);
  651.             timing_info.chars += chars;
  652.             if (showtype == XSHOW || showtype == RMSHOW)
  653.             {
  654.                 timing_info.kerns += characterspacing(font, textstrings[i], charspace, justify,
  655.                         kern, track, (showtype == XSHOW));
  656.                 if (showtype == XSHOW)
  657.                 {
  658.                     PSmoveto(textstart[i][0], textstart[i][1]);
  659.                     PSxshow(textstrings[i], charspace, chars);
  660.                 }
  661.                 else
  662.                 {
  663.                     PSmoveto(textstart[i][0], textstart[i][1]);
  664.                     for (j = 0, last = -1, x = 0.0; j < chars; j++)
  665.                     {
  666.                         if (charspace[j] != 0)
  667.                         {
  668.                             if (x == 0.0)
  669.                                 PSWShow(&textstrings[i][last+1], j - last);
  670.                             else
  671.                                 PSWRmovetoShow(x, &textstrings[i][last+1], j - last);
  672.                             last = j;
  673.                             x = charspace[j];
  674.                         }
  675.                     }
  676.                     if (x == 0.0)
  677.                     {
  678.                         if (j-last > 0)
  679.                             PSWShow(&textstrings[i][last+1], j - last);
  680.                     }
  681.                     else
  682.                     {
  683.                         if (j-last-1 > 0)
  684.                             PSWRmovetoShow(x, &textstrings[i][last+1], j - last -1);
  685.                     }
  686.                 }
  687.             }
  688.             else 
  689.             {
  690.                 ResetShowStruct(&s);
  691.                 AddString(&s, textstrings[i]);
  692.                 AddMoveto(&s, 0, textstart[i][0], textstart[i][1]);
  693.                 timing_info.kerns += showstructure(font, textstrings[i], &s, justify,
  694.                         kern, track);
  695.                 ShowAny(&s);
  696.             }
  697.         }
  698.     }
  699.     PSWReturnTime(&ElapsedTime);
  700.     if (trace)
  701.         DPSTraceContext(DPSGetCurrentContext(), NO);
  702.     PSsetwindowtype(NX_BUFFERED, [window  windowNum]);
  703.  
  704.     timing_info.time += ElapsedTime;
  705.     timing_info.reshows++;
  706.  
  707.     return self;
  708. }
  709.  
  710. /*
  711. *    Erase the fields in the interface, whiten the backdrop, check the cases
  712. *    for showing the text and call the showText: method appropriately. 
  713. */
  714. - drawSelf:(const NXRect *)r :(int) count
  715. {
  716.     BOOL        temp;
  717.  
  718.     if (eraseFields)
  719.         [self  eraseFields:self];
  720.  
  721.     PSsetgray(NX_WHITE);
  722.     NXRectFill(r);
  723.     PSsetgray(NX_BLACK);
  724.  
  725.     if (track)
  726.         PStranslate(-45, 0);
  727.         
  728.     if (compareKern)
  729.     {
  730.         temp = kern;
  731.         kern = YES;
  732.         [self  showText:r];
  733.         
  734.         kern = NO;
  735.         PStranslate(0.0, 10.0);    
  736.         [self  showText:r];
  737.         kern = temp;
  738.     }
  739.     else if (compareWidths)
  740.     {
  741.         temp = screen;
  742.         screen = NO;
  743.         [self  showText:r];
  744.         
  745.         screen = YES;
  746.         PStranslate(0.0, 10.0);    
  747.         [self  showText:r];
  748.         screen = temp;
  749.     }        
  750.     else
  751.         [self  showText:r];
  752.         
  753.     return self;            
  754. }
  755.  
  756. @end
  757.